package framework.utils;

import java.io.InputStream;
import java.io.IOException;
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

/**
 * @author	Orlin Tomov
 * @version	0.2
 *
 */
public class Xml {

	private static final boolean validation = false;
	private static final boolean ignoreWhitespace = true;
	private static final boolean ignoreComments = true;
	private static final boolean putCDATAIntoText = true;
	private static final boolean createEntityRefs = true;
	private static Logger log = Logger.getRootLogger();

	public static Document parse(InputStream in) throws SAXException, IOException {
		// Step 1: create a DocumentBuilderFactory
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// Optional: set various configuration options
		factory.setValidating(validation);
		factory.setIgnoringComments(ignoreComments);
		factory.setIgnoringElementContentWhitespace(ignoreWhitespace);
		factory.setCoalescing(putCDATAIntoText);
		// The opposite of creating entity ref nodes is expanding them inline
		factory.setExpandEntityReferences(createEntityRefs);

		// Step 2: create a DocumentBuilder
		DocumentBuilder builder;
		try {
			builder = factory.newDocumentBuilder();
		} catch (ParserConfigurationException exception) {
			/**/log.error(exception.getMessage(), exception);
			return null;
		}

		// Step 3: parse the input file to get a Document object
		//try {
		return builder.parse(in);
		//} catch (IOException exception) {
		//  /**/Server.log.error(exception.getMessage(), exception);
		//  return null;
		//} catch (SAXException exception) {
		//  /**/Server.log.error(exception.getMessage(), exception);
		//  return null;
		//}
	}

	public static Node nextNode(Node node, String name) {
		while (node != null && (node.getNodeType() != 1 || !node.getNodeName().equalsIgnoreCase(name))) {
			node = node.getNextSibling();
			if (node == null) {
				return null;
			}
		}
		return node;
	}

	public static Node tagNode(Node parent, String name) {
		if (parent == null) {
			return null;
		} else {
			Node node = parent.getFirstChild();
			return nextNode(node, name);
		}
	}

	public static String nodeValue(Node node) {
		if (node == null || node.getFirstChild() == null) {
			return null;
		} else {
			String value = node.getFirstChild().getNodeValue();
			return value.trim();
		}
	}

	public static String tagAttrValue(Node parent, String name) {
		for (int i = 0; i < parent.getAttributes().getLength(); i++) {
			Node nodeAttr = parent.getAttributes().item(i);
			if (nodeAttr.getNodeName().equalsIgnoreCase(name)) {
				return nodeAttr.getNodeValue().trim();
			}
		}
		return null;
	}

	public static String toString(Document document) {
		try {
			Transformer transformer = TransformerFactory.newInstance().newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");

			//initialize StreamResult with File object to save to file
			StreamResult result = new StreamResult(new StringWriter());
			DOMSource source = new DOMSource(document);
			transformer.transform(source, result);

			return result.getWriter().toString();
		} catch (TransformerConfigurationException exception) {
			/**/log.error(exception.getMessage(), exception);
		} catch (TransformerFactoryConfigurationError exception) {
			/**/log.error(exception.getMessage(), exception);
		} catch (TransformerException exception) {
			/**/log.error(exception.getMessage(), exception);
		}
		return null;
	}
}
